/*******************************************************************************
F64PlusInterface.c

===============================================================================
Copyright (c) 2010, Centeye, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Centeye, Inc. nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL CENTEYE, INC. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================


Code to interface with Faraya64plus vision chip via the NAVio12B interface

This code interfaces with and performs basic operations on the Faraya64plus
vision chip. This code assumes that the NAVio12B port interface has been
established in AVR8sa1os1.

Origin:
Adapted from various AVR8 prototype libraries by Travis Young.

Change Log:
2010 May 21, Friday, birth
2010 August 6, Friday, documentation

Possible changes:
1) Modify functions to remove referene to specific vision chip, so that different
variations of this library may be incorporated.
******************************************************************************/



#include "F64PlusInterface.h"
#include <avr/io.h>
#include "AVR8sa1os101.h"
#include "ApplicationPrototype.h"
#include "I2CSupport.h"

//////////////////////////////////////////////////////////////////////////////
// PROCESS_F64_COMMAND: Process a command for the F64 vision chip.
//
// This function is called by process_commands(). Generally this code should
// be static.
//
// Possible edits: None.
//////////////////////////////////////////////////////////////////////////////
void process_F64_command(unsigned char cmd0, unsigned char cmd1)
{

	switch (cmd0) {
		// THESE ARE VISION CHIP COMMANDS

		//change NBIAS1
		case COMM_CMD_NBIAS1:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.NBias1) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_NBIAS1, cmd1);
//				BiasSettings.UpdateReq = 1;
				open_vault();
				// there shouldn't be the need to send these commands three
				// times, but we do this anyway.
				send_command(VCF64_CMD_NBIAS1+cmd1);
				send_command(VCF64_CMD_NBIAS1+cmd1);
				send_command(VCF64_CMD_NBIAS1+cmd1);
				close_vault();
debug.read[10] = cmd1;
			}
			break;

		//change VREF
		case COMM_CMD_VREF:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.VREF) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_VREF, cmd1);
//				BiasSettings.UpdateReq = 1;
				open_vault();
				send_command(VCF64_CMD_VREF+cmd1);
				send_command(VCF64_CMD_VREF+cmd1);
				send_command(VCF64_CMD_VREF+cmd1);
				close_vault();				
debug.read[11] = cmd1;
			}
			break;

		//change NBIAS2
		case COMM_CMD_NBIAS2:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.NBias2) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_NBIAS2, cmd1);
//				BiasSettings.UpdateReq = 1;
				open_vault();
				send_command(VCF64_CMD_NBIAS2+cmd1);
				send_command(VCF64_CMD_NBIAS2+cmd1);
				send_command(VCF64_CMD_NBIAS2+cmd1);
				close_vault();
debug.read[12] = cmd1;
			}
			break;

		//change PRSUPPLY
		case COMM_CMD_PRSUPPLY:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.PRSupply) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_PRSUPPLY, cmd1);
//				BiasSettings.UpdateReq = 1;
				open_vault();
				send_command(VCF64_CMD_PRSUPPLY+cmd1);
				send_command(VCF64_CMD_PRSUPPLY+cmd1);
				send_command(VCF64_CMD_PRSUPPLY+cmd1);
				close_vault();
debug.read[13] = cmd1;
			}
			break;

		//change AOUT bias
		case COMM_CMD_ANALOGOUTBIAS:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.AnalogOutBias) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_ANALOGOUTBIAS, cmd1);
//				BiasSettings.UpdateReq = 1;
				open_vault();
				send_command(VCF64_CMD_ANALOGOUTBIAS+cmd1);
				send_command(VCF64_CMD_ANALOGOUTBIAS+cmd1);
				send_command(VCF64_CMD_ANALOGOUTBIAS+cmd1);
				close_vault();
debug.read[14] = cmd1;
			}
			break;

		case COMM_CMD_LREG1:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				send_command(VCF64_CMD_LREG1+cmd1);	
			}
			break;

		case COMM_CMD_LREG2:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				send_command(VCF64_CMD_LREG2+cmd1);	
			}
			break;

		case COMM_CMD_LREG3:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				send_command(VCF64_CMD_LREG3+cmd1);	
			}
			break;

		case COMM_CMD_LREG4:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				send_command(VCF64_CMD_LREG4+cmd1);	
			}
			break;

		case COMM_CMD_ADCOP:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				send_command(VCF64_CMD_ADCOP+cmd1);	
			}
			break;

		case COMM_CMD_RESB:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.ResB) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_RESB, cmd1);
//				BiasSettings.UpdateReq = 1;
				send_command(VCF64_CMD_RESB+cmd1);
				send_command(VCF64_CMD_RESB+cmd1);
				send_command(VCF64_CMD_RESB+cmd1);
debug.read[15] = cmd1;
			}
			break;

//			if(cmd1)
//			send_command(resb+cmd1);	
			break;

		case COMM_CMD_REST:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.ResT) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_REST, cmd1);
//				BiasSettings.UpdateReq = 1;
				send_command(VCF64_CMD_REST+cmd1);
				send_command(VCF64_CMD_REST+cmd1);
				send_command(VCF64_CMD_REST+cmd1);
debug.read[16] = cmd1;
			}
			break;

		case COMM_CMD_YUKNB:
			if( (cmd1 & 0xC0) == 0x40) {
				cmd1 &= 0x3F;
				*(BiasSettings.YukNBias) = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_YUKNB, cmd1);
//				BiasSettings.UpdateReq = 1;
				send_command(VCF64_CMD_YUKNBIAS+cmd1);
				send_command(VCF64_CMD_YUKNBIAS+cmd1);
				send_command(VCF64_CMD_YUKNBIAS+cmd1);
debug.read[17] = cmd1;
			}
			break;

		case COMM_CMD_AMPTYPE:
			if( (cmd1 & 0xF0) == 0x50) {
				cmd1 &= 0x0F;
				*Amp_Type = cmd1;
				eeprom_update_byte((unsigned char*)EEP_VC_AMPTYPE, cmd1);
			}
			break;

	} // switch

}


//////////////////////////////////////////////////////////////////////////////
// PROCESS_F64_TRANSMIT: Process an application command.
//
// This function is called by process_transmit() and initializes the 
// transmit buffer structure to send arrays associated with the vision chip
//
// Possible edits: Plenty...
//////////////////////////////////////////////////////////////////////////////
void process_F64_transmit(unsigned char array_to_transmit)
{
	switch (array_to_transmit) {
		// Reads the vision chip calibration bias values, see VC_init() for order
		case COMM_ATT_VC_BIASES:
			xmtbuf.comm_att = COMM_ATT_VC_BIASES;
			xmtbuf.read = BiasSettingsATT.read;
			xmtbuf.read_length = BiasSettingsATT.read_length;
			xmtbuf.locked = &(BiasSettingsATT.locked);
			break;
	}
}

//////////////////////////////////////////////////////////////////////////////
// OPEN_VAULT: "Open the vault" e.g. turn biasswitch on so that biases may
// be adjusted and connectVDDA may be turned on or off.
//
// 
//////////////////////////////////////////////////////////////////////////////
void open_vault(void)
{
	LoadCmd(VCF64_CMD_KEY1);
	LoadCmd(VCF64_CMD_KEY2);
	LoadCmd(VCF64_CMD_KEY3);
}

//////////////////////////////////////////////////////////////////////////////
// CLOSE_VAULT: "Close the vault" e.g. turn biasswitch off so that biases and
// connectVDDA are protected.
//
// Possible change: rather than inverted key, just set to all zero
//////////////////////////////////////////////////////////////////////////////
void close_vault(void)
{
	LoadCmd(VCF64_CMD_KEY1_INV);
	LoadCmd(VCF64_CMD_KEY2_INV);
	LoadCmd(VCF64_CMD_KEY3_INV);
}

//////////////////////////////////////////////////////////////////////////////
// INIT_BIASES: Initial setup of biases.
//
// This function is called at sensor power up
//
// Possible changes: 1) vary the biases depending on the power supply voltage
// used. 2) incorporate this into a more general bias adjustment scheme
//////////////////////////////////////////////////////////////////////////////
void init_biases(void)
{
	//mark update flag
	BiasSettings.UpdateReq = 1;
	
	unsigned char a;
	a = eeprom_read_byte((unsigned char*)EEP_VC_NBIAS1);
	*(BiasSettings.NBias1) = ( a < 0x40 ? a : NBIAS1_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_VREF);
	*(BiasSettings.VREF) = ( a < 0x40 ? a : VREF_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_NBIAS2);
	*(BiasSettings.NBias2) = ( a < 0x40 ? a : NBIAS2_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_PRSUPPLY);
	*(BiasSettings.PRSupply) = ( a < 0x40 ? a : PRSUPPLY_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_ANALOGOUTBIAS);
	*(BiasSettings.AnalogOutBias) = ( a < 0x40 ? a : ANALOGOUTBIAS_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_YUKNB);
	*(BiasSettings.YukNBias) = ( a < 0x40 ? a : YUKNBIAS_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_RESB);
	*(BiasSettings.ResB) = ( a < 0x40 ? a : RESB_DEFAULT );
	a = eeprom_read_byte((unsigned char*)EEP_VC_REST);
	*(BiasSettings.ResT) = ( a < 0x40 ? a : REST_DEFAULT );

}


//////////////////////////////////////////////////////////////////////////////
// VC_init: Initialize variables associated with vision chip as well as
// vision chip itself.
//
// This function is part of the sensor initialization routine
//
// Possible changes: This function might be better placed into the firmware 
// section, unless we make a generic initialization routine. We also might
// want to modify this according to the supply voltage.
//////////////////////////////////////////////////////////////////////////////
void VC_init(void)
{

	//set linear regulator.
	// LREG3 controls voltage, Assumes 5V supply and generates VDDA = 4.08V
	//   for 0x06 (default)
	// See table in Faraya documentation for values.
	LoadCmd((VCF64_CMD_LREG1+0x24));
	LoadCmd((VCF64_CMD_LREG2+0x04));
	LoadCmd((VCF64_CMD_LREG3+0x09)); // using 3.12V with our 3.3V i2c rail (0x09)
	LoadCmd((VCF64_CMD_LREG4+0x10));

	//set up on-chip adc
	LoadCmd((VCF64_CMD_ADCOP+0x02));
	LoadCmd((VCF64_CMD_RESB+0x3F));
	LoadCmd((VCF64_CMD_REST+0x00));

	// Set the BiasSettings pointers to the ATT array
	BiasSettingsATT.read_length = 9;
	BiasSettings.NBias1 = &(BiasSettingsATT.read[0]);
	BiasSettings.VREF = &(BiasSettingsATT.read[1]);
	BiasSettings.NBias2 = &(BiasSettingsATT.read[2]);
	BiasSettings.PRSupply =  &(BiasSettingsATT.read[3]);
	BiasSettings.AnalogOutBias = &(BiasSettingsATT.read[4]);
	BiasSettings.YukNBias = &(BiasSettingsATT.read[5]);
	BiasSettings.ResB = &(BiasSettingsATT.read[6]);
	BiasSettings.ResT = &(BiasSettingsATT.read[7]);
	Amp_Type = &(BiasSettingsATT.read[8]);

	init_biases();  	//set biases

	unsigned char a = eeprom_read_byte((unsigned char*)EEP_VC_AMPTYPE);
	*Amp_Type = ( a < 5 ? a : 0 );

	//connect VDDA
	open_vault();
	LoadCmd(VCF64_CMD_CONNECTVDDA);
	close_vault();
}


//////////////////////////////////////////////////////////////////////////////
// SEND_COMMAND: send a 12 bit command to the vision chip via NAVio12B,
// with the command being specified as a variable
//
// Called for tasks such as setting a row or column
//////////////////////////////////////////////////////////////////////////////
void send_command(short int data)
{
	LoadCmd(data);
}


//////////////////////////////////////////////////////////////////////////////
// SET_BIASES: Set all the biases according to the values set in the bias
// settings data structure.
//
// Possible changes: Merge with init_biases? Modify so that only needed
// biases are updated?
//////////////////////////////////////////////////////////////////////////////
void set_biases(void)
{
	//open vault, load bias commands, close vault
	open_vault();
	LoadCmd((VCF64_CMD_NBIAS1+ *(BiasSettings.NBias1)));
	LoadCmd((VCF64_CMD_NBIAS2+ *(BiasSettings.NBias2)));
	LoadCmd((VCF64_CMD_VREF+ *(BiasSettings.VREF)));
	LoadCmd((VCF64_CMD_ANALOGOUTBIAS+ *(BiasSettings.AnalogOutBias)));
	LoadCmd((VCF64_CMD_PRSUPPLY+ *(BiasSettings.PRSupply)));
	LoadCmd((VCF64_CMD_YUKNBIAS+ *(BiasSettings.YukNBias)));
	LoadCmd((VCF64_CMD_RESB+ *(BiasSettings.ResB)));
	LoadCmd((VCF64_CMD_REST+ *(BiasSettings.ResT)));
	close_vault();
		
	// mark biases updated
	BiasSettings.UpdateReq = 0;
}

//////////////////////////////////////////////////////////////////////////////
// LOADCAPS: Loads one row from the amplifiers to the capacitors
//
// Possible changes: Rename?
//////////////////////////////////////////////////////////////////////////////
void loadcaps(void)
{
	//loadcaps for smoothed image
	LoadCmd((VCF64_CMD_MISC+0x04));
	LoadCmd((VCF64_CMD_MISC+0x06));
	LoadCmd((VCF64_CMD_MISC+0x04));
}

//////////////////////////////////////////////////////////////////////////////
// AMPLIFY: Amplify a row of signals output by the focal plane
//
// This function is called every time a row is amplified
//
// Possible changes: Rename?
//////////////////////////////////////////////////////////////////////////////
void amplify(void)
{

	//select amplify
//	LoadCmd((midconfig+0x02));
	
	switch(*Amp_Type)
	{
	case 0:	//unity gain?
		LoadCmd((VCF64_CMD_MIDCONFIG+0x0C)); // shtcap=1, sunity=1, samp=0
		LoadCmd((VCF64_CMD_MISC+0x16)); // scsc=1, vdds=0, rpix=1, lcap=1, scap=0
		LoadCmd((VCF64_CMD_MIDOP+0x01)); // caps disconnected, phi=0
		break;
	case 1: //big - small cap
		LoadCmd((VCF64_CMD_MIDCONFIG+0x02)); // shtcap=0, sunity=0, samp=1
		LoadCmd((VCF64_CMD_MISC+0x14)); // scsc=1, vdds=0, rpix=1, lcap=0, scap=0
		LoadCmd((VCF64_CMD_MIDOP+0x1A));
		Delay1(5);
		LoadCmd((VCF64_CMD_MIDOP+0x19));
		LoadCmd((VCF64_CMD_MIDOP+0x25));
		Delay1(5);
		break;
	case 2: //small cap
		LoadCmd((VCF64_CMD_MIDCONFIG+0x02)); // shtcap=0, sunity=0, samp=1
		LoadCmd((VCF64_CMD_MISC+0x14)); // scsc=1, vdds=0, rpix=1, lcap=0, scap=0
		LoadCmd((VCF64_CMD_MIDOP+0x06)); // scin1, phi
		Delay1(5);
		LoadCmd((VCF64_CMD_MIDOP+0x05)); // scin1, nphi
		LoadCmd((VCF64_CMD_MIDOP+0x09)); // scref1, nphi
		Delay1(5);
		break;
	case 3: //big cap
		LoadCmd((VCF64_CMD_MIDCONFIG+0x02)); // shtcap=0, sunity=0, samp=1
		LoadCmd((VCF64_CMD_MISC+0x14)); // scsc=1, vdds=0, rpix=1, lcap=0, scap=0
		LoadCmd((VCF64_CMD_MIDOP+0x12)); // scin2, phi
		Delay1(5);
		LoadCmd((VCF64_CMD_MIDOP+0x11)); // scin2, nphi
		LoadCmd((VCF64_CMD_MIDOP+0x21)); // scref2, nphi
		Delay1(5);
		break;
	case 4: //big + small cap
		LoadCmd((VCF64_CMD_MIDCONFIG+0x02)); // shtcap=0, sunity=0, samp=1
		LoadCmd((VCF64_CMD_MISC+0x14)); // scsc=1, vdds=0, rpix=1, lcap=0, scap=0
		LoadCmd((VCF64_CMD_MIDOP+0x16)); // scin2, scin1, phi
		Delay1(5);
		LoadCmd((VCF64_CMD_MIDOP+0x15)); // scin2, scin1, nphi
		LoadCmd((VCF64_CMD_MIDOP+0x29)); // scref2, scref1, nphi
		Delay1(5);
		break;
	default:break;
	}	
}

//////////////////////////////////////////////////////////////////////////////
// SMOOTH_IMAGE: simple smoothing of image, using binning. Variables "row" and
// "col" dictate how much to bin in the row and columnd directions. Set these
// values to 1 for no binning.
//
// Possible changes: Possibly rename. Add either here or elsewhere the
// ability to do offset downsampling, perhaps as another function. The
// global variables "row" and "col" could be renamed.
//////////////////////////////////////////////////////////////////////////////
void smooth_image(int row,int col)
{
	//close desired switches
	switch(row)
	{
	case 1:LoadCmd((VCF64_CMD_VSW+0x00));break;
	case 2:LoadCmd((VCF64_CMD_VSW+0x55));break;
	case 4:LoadCmd((VCF64_CMD_VSW+0x77));break;
	case 8:LoadCmd((VCF64_CMD_VSW+0x7F));break;
	case 64:LoadCmd((VCF64_CMD_VSW+0xFF));break;
	}
	
	switch(col)
	{
	case 1:LoadCmd((VCF64_CMD_HSW+0x00));break;
	case 2:LoadCmd((VCF64_CMD_HSW+0x55));break;
	case 4:LoadCmd((VCF64_CMD_HSW+0x77));break;
	case 8:LoadCmd((VCF64_CMD_HSW+0x7F));break;
	case 64:LoadCmd((VCF64_CMD_HSW+0xFF));break;
	}
	
	//open switches
	LoadCmd((VCF64_CMD_HSW+0x00));
	LoadCmd((VCF64_CMD_VSW+0x00));	
}



